package com.squareup.okhttp;

import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.app.MApplication;
import com.google.gson.JsonObject;
import com.idroid.utils.CacheTool.MD5Util;
import com.idroid.utils.EmojiFilter;
import com.lidroid.util.IPUtils;

import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * @author yiyi
 * @date 2015年11月2日
 */

public class OkHttp {

    private static OkHttpClient sOkHttpClient = new OkHttpClient();       //用于普通请求时的超时限制(默认25s)
    public static final MediaType ContentType = MediaType.parse("application/json; charset=utf-8");
    public static String version = "1.0.0";
    static Handler uiHandler;

    public static final String FIXED_AUZ = "Basic ";
    public static String MEMBER_ID="";
    public static String SIG = "";
    private final static long mTimeSencond = 15;
    public static String KJB_APP_Token="";//后台token字段
    public static String KJB_DEVICE_ID="";

    static {
        OkHttpClient.Builder builder = sOkHttpClient.newBuilder();
        builder.connectTimeout(mTimeSencond, TimeUnit.SECONDS);
        builder.readTimeout(mTimeSencond, TimeUnit.SECONDS);
        builder.writeTimeout(mTimeSencond, TimeUnit.SECONDS);
        uiHandler = new Handler(Looper.getMainLooper());
    }

    public static OkHttpClient getClient() {
        return sOkHttpClient;
    }


    public static void addInterceptor(Interceptor interceptor) {
        OkHttpClient.Builder builder = sOkHttpClient.newBuilder();
        builder.connectTimeout(mTimeSencond, TimeUnit.SECONDS);
        builder.readTimeout(mTimeSencond, TimeUnit.SECONDS);
        builder.writeTimeout(mTimeSencond, TimeUnit.SECONDS);
        builder.addInterceptor(interceptor);
        sOkHttpClient = builder.build();
    }

    public static void setOkHttpSSL(InputStream inputStream){
        X509TrustManager trustManager;
        SSLSocketFactory sslSocketFactory;
        try {
            trustManager = trustManagerForCertificates(inputStream);//以流的方式读入证书
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{trustManager}, null);
            sslSocketFactory = sslContext.getSocketFactory();
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
        HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };

        OkHttpClient.Builder builder = sOkHttpClient.newBuilder();
        builder.sslSocketFactory(sslSocketFactory, trustManager);
        builder.hostnameVerifier(DO_NOT_VERIFY);
        sOkHttpClient = builder.build();
    }

    /**
     * 添加password
     * @param password
     * @return
     * @throws GeneralSecurityException
     */
    private static KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {
        try {
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); // 这里添加自定义的密码，默认
            InputStream in = null; // By convention, 'null' creates an empty key store.
            keyStore.load(in, password);
            return keyStore;
        } catch (IOException e) {
            throw new AssertionError(e);
        }
    }

    private static X509TrustManager trustManagerForCertificates(InputStream in)
            throws GeneralSecurityException {
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
        if (certificates.isEmpty()) {
            throw new IllegalArgumentException("expected non-empty set of trusted certificates");
        }

        // Put the certificates a key store.
        char[] password = "password".toCharArray(); // Any password will work.
        KeyStore keyStore = newEmptyKeyStore(password);
        int index = 0;
        for (Certificate certificate : certificates) {
            String certificateAlias = Integer.toString(index++);
            keyStore.setCertificateEntry(certificateAlias, certificate);
        }

        // Use it to build an X509 trust manager.
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
                KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(keyStore, password);
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
            throw new IllegalStateException("Unexpected default trust managers:"
                    + Arrays.toString(trustManagers));
        }
        return (X509TrustManager) trustManagers[0];
    }

    private static SSLSocketFactory getCertificates(InputStream certificates) {
        try {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            int index = 0;
            String certificateAlias = Integer.toString(index++);
            keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificates));
            if (certificates != null)
                certificates.close();
            SSLContext sslContext = SSLContext.getInstance("TLS");
            TrustManagerFactory trustManagerFactory =
                    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void setCache(Cache cache) {

        OkHttpClient.Builder builder = sOkHttpClient.newBuilder();
        builder.connectTimeout(mTimeSencond, TimeUnit.SECONDS);
        builder.readTimeout(mTimeSencond, TimeUnit.SECONDS);
        builder.writeTimeout(mTimeSencond, TimeUnit.SECONDS);
        builder.cache(cache);
        sOkHttpClient = builder.build();
        uiHandler = new Handler(Looper.getMainLooper());
    }


    public static void cancelAll(Object tag) {
        for (Call call : sOkHttpClient.dispatcher().queuedCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
        for (Call call : sOkHttpClient.dispatcher().runningCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
    }

    /****************************针对需要带Token的加密请求头调用(用于发送手机短信验证码的接口)************************************/
    /**
     * Post方式发起MD5加密请求
     *
     * @param url
     * @param params
     * @param responseCallback
     */
    public static void post_md5(String url, Params params, RespondCallBack responseCallback, String tag) {
        String toJson = "";
        String md5str = "";
        if (params == null) {
            params = new Params();
            toJson = createBodyJson(url, params);
        } else {
            toJson = createBodyJson(url, params);
            StringBuffer sb = new StringBuffer();
            try {
                JSONObject tmp = new JSONObject(toJson);
                Iterator<?> it = tmp.keys();
                while (it.hasNext()) {//遍历JSONObject
                    String key = it.next().toString();
                    String value = tmp.getString(key);
                    sb.append(key + "=" + value + "&");
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
            String tempStr = sb.toString().substring(0, sb.toString().length() - 1);
            md5str = MD5Util.getMD5(tempStr.toLowerCase() + "{mall_mall}");
        }
        post_md5(url, toJson, md5str, responseCallback, tag);
    }

    /**
     * Post方式发起MD5加密带Token
     *
     * @param url
     * @param json
     * @param responseCallback
     * @param tag
     */
    public static void post_md5(String url, String json, String token, RespondCallBack responseCallback, String tag) {
        if (TextUtils.isEmpty(json))
            return;
        if (EmojiFilter.containsEmoji(json)) {
            json = EmojiFilter.filterEmoji(json);
        }
        /** OKHttp新增登录认证信息*/
        String auzStr = FIXED_AUZ + SIG;
        RequestBody body = RequestBody.create(ContentType, json);
        Request request = commonHeaderBuilder().addHeader("Token", token).addHeader("Authorization", auzStr.replaceAll("\n", "")).url(url).tag(tag).post
                (body).build();
        enqueue(request, responseCallback);
    }

    /**
     * 针对对手机号发送验证码的接口时对手机号进行加密
     */
    public static void post_phoneMD5(String url, Params params,String phone, RespondCallBack responseCallback, String tag){
        if (params == null) {
            params = new Params();
        }
        String toJson = createBodyJson(url, params);
        String phoneToken = MD5Util.getMD5("phone="+ phone + "{mall_mall}");
        post_md5(url,toJson,phoneToken,responseCallback,tag);
    }
    /****************************针对需要带Token的加密请求头调用(用于发送手机短信验证码的接口)************************************/


    /**
     * Post方式发起请求
     *
     */
    public static void post(String url, Params params, RespondCallBack responseCallback, String tag) {
        if (params == null) {
            params = new Params();
        }
        String toJson = createBodyJson(url, params);
        responseCallback.mUrl=url;
        responseCallback.toJson=toJson;
        responseCallback.getorpost="post";
        post(url, toJson, responseCallback, tag);
    }


    /**
     * 参数转化为json
     */
    private static String createBodyJson(String url, Params params) {
        String toJson = JSON.toJSONString(params.list());
        return toJson;
    }

    /**
     * 直接封装好的json做为参数
     *
     * @param url
     * @param json
     * @param responseCallback
     * @param tag
     */
    public static void post(String url, String json, RespondCallBack responseCallback, String tag) {
        if (TextUtils.isEmpty(json))
            return;
        if (EmojiFilter.containsEmoji(json)) {
            json = EmojiFilter.filterEmoji(json);
        }
        /** OKHttp新增登录认证信息*/
        String auzStr = FIXED_AUZ + SIG;
        RequestBody body = RequestBody.create(ContentType, json);
        Request request = commonHeaderBuilder().addHeader("Authorization", auzStr.replaceAll("\n", "")).url(url).tag(tag).post
                (body).build();
        enqueue(request, responseCallback);
    }

    /**
     * 初始化header
     */
    public static Request.Builder commonHeaderBuilder() {
        String ip = IPUtils.getHostIp() == null ? "" : IPUtils.getHostIp();
        return new Request.Builder().header("X-Message-Sender", "KUAIJIE").addHeader("PlatformType", "1")
                .addHeader("IP", ip)
                .addHeader("PhoneModel", android.os.Build.BRAND+"_"+android.os.Build.MODEL)//对应厂商+机型
                .addHeader("PhoneVersion", android.os.Build.VERSION.RELEASE)//手机版本
                .addHeader("MemberId",MEMBER_ID)
                .addHeader("AppId",android.os.Build.SERIAL)
                .addHeader("AppVersion",version)
                .addHeader("KJB-APP-Token",KJB_APP_Token)
                .addHeader("KJB-DEVICE-ID",getKjbDeviceId());
    }


    public static void get(String url,Params params,RespondCallBack responseCallback, String tag){
        String reqUrl = paramsUrl(url, params);
        responseCallback.mUrl=url;
        responseCallback.mParams=params;
        responseCallback.getorpost="get";
        get(reqUrl,responseCallback,tag);
    }

    /**
     * Get方式发送请求
     * @param responseCallback
     */
    public static void get(String mreqUrl, RespondCallBack responseCallback, String tag) {
        /** OKHttp新增登录认证信息*/
        String auzStr = FIXED_AUZ + SIG;
        String reqUrl = mreqUrl;
        Request request = commonHeaderBuilder().addHeader("Authorization", auzStr.replaceAll("\n", "")).url(reqUrl).tag(tag)
                .build();
        enqueue(request, responseCallback);
    }


    /**
     * GET请求方式，不使用缓存数据
     *
     * @param url
     * @param params
     * @param responseCallback
     * @param tag
     */
    public static void getNoCache(String url, Params params, RespondCallBack responseCallback, String tag) {
        /** OKHttp新增登录认证信息*/
        params.add("nocache", System.currentTimeMillis());
        String auzStr = FIXED_AUZ + SIG;
        String reqUrl = paramsUrl(url, params);
        Request request = commonHeaderBuilder().addHeader("Authorization", auzStr.replaceAll("\n", "")).url(reqUrl).tag(tag)
                .build();
        enqueue(request, responseCallback);
    }

    public final static String buildBodyJson(String url, Params params) {
        String toJson = createBodyJson(url, params);
        return toJson;
    }

    /**
     * url添加参数
     */
    public final static String paramsUrl(String url, Params params) {
        String reqUrl = url;
        if (params != null) {
            Set<Entry<String, Object>> tempSet = params.list().entrySet();
            List<BasicNameValuePair> tempList = new ArrayList<BasicNameValuePair>();
            for (Entry<String, Object> temp : tempSet) {
                if (!TextUtils.isEmpty(temp.getKey()) && temp.getValue() != null)
                    tempList.add(new BasicNameValuePair(temp.getKey(), temp.getValue().toString()));
            }
            reqUrl = attachHttpGetParams(url, tempList);

        }
        return reqUrl;
    }

    /**
     * 开启异步线程访问网络
     *
     * @param request
     * @param responseCallback
     */
    public static void enqueue(final Request request, RespondCallBack responseCallback) {
        sOkHttpClient.newCall(request).enqueue(CommonCallback.obtain(responseCallback));
    }

    private static final String CHARSET_NAME = "UTF-8";

    /**
     * 这里使用了HttpClinet的API。只是为了方便
     *
     * @param params
     * @return
     */
    public static String formatParams(List<BasicNameValuePair> params) {
        return URLEncodedUtils.format(params, CHARSET_NAME);
    }

    /**
     * 为HttpGet 的 url 方便的添加多个name value 参数。
     *
     * @param url
     * @param params
     * @return
     */
    public static String attachHttpGetParams(String url, List<BasicNameValuePair> params) {
        return url + "?" + formatParams(params);
    }

    /**
     * 为HttpGet 的 url 方便的添加1个name value 参数。
     *
     * @param url
     * @param name
     * @param value
     * @return
     */
    public static String attachHttpGetParam(String url, String name, String value) {
        return url + "?" + name + "=" + value;
    }


    /**
     * 直接把网络文件存到手机
     *
     * @param url
     * @param listener
     */
    public static void downloadFileFromUrl(String url, DownLoadCallback.DownLoadCallBackListener listener) {
        Request request = commonHeaderBuilder().url(url).build();
        sOkHttpClient.newCall(request).enqueue(DownLoadCallback.obtain(listener));
    }

    /**
     * 不返回body的请求，可以用来判断链接是否可用
     *
     * @param url
     * @param listener
     */
    public static void judgeCode(String url, DownLoadCallback.DownLoadCallBackListener listener) {
        try {
            Request request = commonHeaderBuilder().url(url).head().build();
            sOkHttpClient.newCall(request).enqueue(DownLoadCallback.obtain(listener));
        } catch (Exception e) {
            listener.onFailure(404, "url不正确");
        }
    }

    public static String getKjbDeviceId() {
        return KJB_DEVICE_ID;
    }

    public static void setKjbDeviceId(String kjbDeviceId) {
        KJB_DEVICE_ID = kjbDeviceId;
    }
}
